<?php

namespace App\Http\Service;

use App\Models\AuctionWinner;
use App\Models\Product;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

// 结束竞价
class FinishBidding
{
    // 结束竞价
    public function handle()
    {
        // 如果没有上架的商品直接退出执行
        if (Product::query()->where('on_sale', Product::IS_SALE)->doesntExist()) {
            return;
        }

        // 开始竞拍
        Product::query()->where('start_at', '<=', Carbon::now())
            ->where('on_sale', Product::IS_SALE)
            ->get()
            ->each(function ($product) {
                $product->type = Product::TYPE_BIDDING;
                $product->save();
            });

        // 竞拍结束, 如果有人参与了竞拍的商品
        Product::query()->where('end_at', '<=', Carbon::now())
            ->where('on_sale', Product::IS_SALE)
            ->get()
            ->each(function (Product $product) {
                if ($product->biddingList) {
                    $maxPrice = $product->biddingList->max('now_price') ?: 0;
                    foreach ($product->biddingList as $value) {
                        if (doubleval($value->now_price) === doubleval($maxPrice)) {
                            // 保存竞拍成功的用户
                            $actionWinner = new AuctionWinner([
                                'price' => $maxPrice
                            ]);

                            $actionWinner->product()->associate($value->product_id);
                            $actionWinner->user()->associate($value->user_id);
                            $actionWinner->save();
                            if (User::query()->find($value->user_id)) {
                                $product->type = Product::TYPE_ADMIN_RECYCLE;   // 管理员回收
                            }
                        }
                    }
                    $product->on_sale = false;  // 停止竞价
                    $product->save();
                } else {
                    $product->on_sale = false;  // 停止竞价
                    $product->type = Product::TYPE_NO_BIDDERS; // 同时打上无人竞拍标签
                    $product->save();
                }
            });

        for ($i = 0; $i < 30; $i ++) {
            $temp[] = $i;
        }

        if (Arr::random($temp) == 1) {
            // 有1 / 30的几率触发自动加价
            $this->autoBid();
        }
    }

    // 自动哄抬价格
    public function autoBid()
    {
        // 随机获取1个管理员账号
        $admin = User::query()->where('is_admin', true)->inRandomOrder()->first();

        // 距离结束还有一个小时, 随机几个商品上操作管理员账号对商品价格进行哄抬
        $count = Product::query()->where('on_sale', Product::IS_SALE)->where('end_at', '<=', Carbon::now()->addMinutes(60))->count();
        $takeNum = intval(intval($count) * 0.4);

        $randomArr = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3];
        $randomNum = Arr::random($randomArr);

        try {// 离竞拍结束还有2小时到1小时50分钟, 如果没有人出价, 那么系统会操作管理员账号进行随机出价
            Product::query()->where('end_at', '<=', Carbon::now()->addMinutes(120))
                ->where('end_at', '>=', Carbon::now()->addMinutes(110))
                ->where('on_sale', Product::IS_SALE)
                ->inRandomOrder()
                ->take($takeNum)
                ->each(
                    function (Product $product) use ($admin, $randomNum) {
                        $money = doubleval($product->minimum_markup) * $randomNum;
                        if (!$product->biddingList) {  // 如果没有人加价的话
                            // 操作管理员账号哄抬价格
                            $product->bidder()->attach(
                                $admin->id,
                                [
                                    'money' => $money,
                                    'now_price' => doubleval($money) + doubleval($product->price),
                                ]
                            );
                        }
                    }
                );


            // 离竞拍结束54 - 58分钟, 没有人出价, 那么系统会操作管理员账号对所有未出价的商品进行出价
            Product::query()->where('end_at', '<=', Carbon::now()->addMinutes(58))
                ->where('end_at', '>=', Carbon::now()->addMinutes(54))
                ->where('on_sale', Product::IS_SALE)
                ->each(
                    function (Product $product) use ($admin, $randomNum) {
                        if ($product->biddingList->isEmpty()) {  // 如果没有人加价的话
                            DB::transaction(
                                function () use ($product, $randomNum, $admin) {
                                    $money = $randomNum * doubleval($product->minimum_markup);
                                    // 获取上一个竞价列表, 增加悲观锁, 防止本条数据被读取, 直到事务结束
                                    $preBiddingProduct = $product->biddingList()->orderBy(
                                        'created_at',
                                        'desc'
                                    )->lockForUpdate()->first();  // 获取上一个人的竞标价格

                                    $nowPrice = $preBiddingProduct ? $preBiddingProduct->now_price + $money : $product->price + $money;

                                    $admin->biddingProduct()->attach(
                                        $product->id,
                                        [
                                            'money' => $money,
                                            'now_price' => $nowPrice,
                                        ]
                                    );
                                }
                            );
                        }
                    }
                );
            $takeNumSecond = intval(intval($count) * 0.2);

            // 离竞拍结束41 - 53分钟, 没有人出价, 那么系统会操作管理员账号对所有未出价的商品进行出价
            Product::query()->where('end_at', '<=', Carbon::now()->addMinutes(53))
                ->where('end_at', '>=', Carbon::now()->addMinutes(41))
                ->where('on_sale', Product::IS_SALE)
                ->take($takeNumSecond)
                ->each(
                    function (Product $product) use ($admin, $randomNum) {
                        if ($product->biddingList->isEmpty()) {  // 如果没有人加价的话
                            DB::transaction(
                                function () use ($product, $randomNum, $admin) {
                                    $money = $randomNum * doubleval($product->minimum_markup);
                                    // 获取上一个竞价列表, 增加悲观锁, 防止本条数据被读取, 直到事务结束
                                    $preBiddingProduct = $product->biddingList()->orderBy(
                                        'created_at',
                                        'desc'
                                    )->lockForUpdate()->first();  // 获取上一个人的竞标价格

                                    $nowPrice = $preBiddingProduct ? $preBiddingProduct->now_price + $money : $product->price + $money;

                                    $admin->biddingProduct()->attach(
                                        $product->id,
                                        [
                                            'money' => $money,
                                            'now_price' => $nowPrice,
                                        ]
                                    );
                                }
                            );
                        }
                    }
                );

            $takeNumThird = intval(intval($count) * 0.4);// 离竞拍结束29-40分钟, 检索所有的商品, 让所有商品都进行数据哄抬
            Product::query()->where('end_at', '<=', Carbon::now()->addMinutes(40))
                ->where('end_at', '>=', Carbon::now()->addMinutes(35))
                ->where('on_sale', Product::IS_SALE)
                ->take($takeNumThird)
                ->each(
                    function (Product $product) use ($admin, $randomNum) {
                        $nowMaxPrice = doubleval($product->biddingList->max('now_price')) ?: 0;
                        // 操作管理员账号, 哄抬价格
                        if ($nowMaxPrice < doubleval($product->ideal_price)) {
                            DB::transaction(
                                function () use ($product, $randomNum, $admin) {
                                    $money = $randomNum * doubleval($product->minimum_markup);
                                    // 获取上一个竞价列表, 增加悲观锁, 防止本条数据被读取, 直到事务结束
                                    $preBiddingProduct = $product->biddingList()->orderBy(
                                        'created_at',
                                        'desc'
                                    )->lockForUpdate()->first();  // 获取上一个人的竞标价格

                                    $nowPrice = $preBiddingProduct ? $preBiddingProduct->now_price + $money : $product->price + $money;

                                    $admin->biddingProduct()->attach(
                                        $product->id,
                                        [
                                            'money' => $money,
                                            'now_price' => $nowPrice,
                                        ]
                                    );
                                }
                            );
                        }
                    }
                );


            // 离竞拍结束还有10分钟
            Product::query()->where('end_at', '<=', Carbon::now()->addMinutes(20))
                ->where('end_at', '>=', Carbon::now()->addMinutes(15))
                ->where('on_sale', Product::IS_SALE)
                ->get()
                ->each(
                    function (Product $product) use ($admin, $randomNum) {
                        $nowMaxPrice = doubleval($product->biddingList->max('now_price')) ?: 0;
                        // 操作管理员账号, 哄抬价格
                        if ($nowMaxPrice < doubleval($product->ideal_price)) {
                            DB::transaction(
                                function () use ($product, $randomNum, $admin) {
                                    $money = $randomNum * doubleval($product->minimum_markup);
                                    // 获取上一个竞价列表, 增加悲观锁, 防止本条数据被读取, 直到事务结束
                                    $preBiddingProduct = $product->biddingList()->orderBy(
                                        'created_at',
                                        'desc'
                                    )->lockForUpdate()->first();  // 获取上一个人的竞标价格

                                    $nowPrice = $preBiddingProduct ? $preBiddingProduct->now_price + $money : $product->price + $money;

                                    $admin->biddingProduct()->attach(
                                        $product->id,
                                        [
                                            'money' => $money,
                                            'now_price' => $nowPrice,
                                        ]
                                    );
                                }
                            );
                        }
                    }
                );


            // 离竞价结束还有3~8分钟
            Product::query()->where('end_at', '<=', Carbon::now()->addMinutes(8))
                ->where('end_at', '>=', Carbon::now()->addMinutes(2))
                ->where('on_sale', Product::IS_SALE)
                ->get()
                ->each(
                    function (Product $product) use ($admin, $randomNum) {
                        $nowMaxPrice = doubleval($product->biddingList->max('now_price')) ?: 0;

                        // 操作管理员账号, 哄抬价格
                        if ($nowMaxPrice < doubleval($product->ideal_price)) {

                            DB::transaction(function () use ($product, $nowMaxPrice, $admin) {
                                    $num = (int)(doubleval($product->ideal_price) - $nowMaxPrice) / 10;
                                    $tempPrice = doubleval($product->minimum_markup);
                                    if ($num >= 1 && $num < 5) {
                                        $money = [
                                            $tempPrice, $tempPrice, $tempPrice, $tempPrice,
                                            $tempPrice, $tempPrice, $tempPrice, $tempPrice * 2,
                                            $tempPrice * 3, $tempPrice * 2
                                        ];
                                    }

                                    if ($num >= 5 && $num < 100) {
                                        $money = Arr::random([$tempPrice, $tempPrice, $tempPrice,  $tempPrice * 2, $tempPrice * 2, $tempPrice * 3]);
                                    }

                                    if ($num >= 100 && $num < 1000) {
                                        $money = Arr::random([$tempPrice, $tempPrice * 2, $tempPrice * 2, $tempPrice * 3, $tempPrice * 4, $tempPrice * 4, $tempPrice * 5]);
                                    }

                                    // 获取上一个竞价列表, 增加悲观锁, 防止本条数据被读取, 直到事务结束
                                    $preBiddingProduct = $product->biddingList()->orderBy(
                                        'created_at',
                                        'desc'
                                    )->lockForUpdate()->first();  // 获取上一个人的竞标价格

                                    $nowPrice = $preBiddingProduct ? $preBiddingProduct->now_price + $money : $product->price + $money;

                                    $admin->biddingProduct()->attach(
                                        $product->id,
                                        [
                                            'money' => $money,
                                            'now_price' => $nowPrice,
                                        ]
                                    );
                                }
                            );
                        }
                    }
                );
        } catch (\Exception $e) {
            Log::info("autoBid error: " . $e->getMessage());
        }
    }
}
